home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 July / EnigmA AMIGA RUN 20 (1997)(G.R. Edizioni)(IT)[!][issue 1997-07 & 08][EAR-CD IV].iso / earcd / text / edit / vim46src.lha / vim-4.6 / src / memfile.c < prev    next >
C/C++ Source or Header  |  1997-03-06  |  29KB  |  1,192 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /* for debugging */
  10. #define CHECK(c, s)    if (c) printf(s)
  11.  
  12. /*
  13.  * memfile.c: Contains the functions for handling blocks of memory which can
  14.  * be stored in a file. This is the implementation of a sort of virtual memory.
  15.  *
  16.  * A memfile consists of a sequence of blocks. The blocks numbered from 0
  17.  * upwards have been assigned a place in the actual file. The block number
  18.  * is equal to the page number in the file. The
  19.  * blocks with negative numbers are currently in memory only. They can be
  20.  * assigned a place in the file when too much memory is being used. At that
  21.  * moment they get a new, positive, number. A list is used for translation of
  22.  * negative to positive numbers.
  23.  *
  24.  * The size of a block is a multiple of a page size, normally the page size of
  25.  * the device the file is on. Most blocks are 1 page long. A Block of multiple
  26.  * pages is used for a line that does not fit in a single page.
  27.  *
  28.  * Each block can be in memory and/or in a file. The block stays in memory
  29.  * as long as it is locked. If it is no longer locked it can be swapped out to
  30.  * the file. It is only written to the file if it has been changed.
  31.  *
  32.  * Under normal operation the file is created when opening the memory file and
  33.  * deleted when closing the memory file. Only with recovery an existing memory
  34.  * file is opened.
  35.  */
  36.  
  37. #if defined MSDOS  ||  defined WIN32
  38. # include <io.h>        /* for lseek(), must be before vim.h */
  39. #endif
  40.  
  41. #include "vim.h"
  42. #include "globals.h"
  43. #include "proto.h"
  44. #include "option.h"
  45. #ifdef HAVE_FCNTL_H
  46. # include <fcntl.h>
  47. #endif
  48.  
  49. /* 
  50.  * Some systems have the page size in statfs.f_bsize, some in stat.st_blksize
  51.  */
  52. #ifdef HAVE_ST_BLKSIZE
  53. # define STATFS stat
  54. # define F_BSIZE st_blksize
  55. # define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
  56. #else
  57. # ifdef HAVE_SYS_STATFS_H
  58. #  include <sys/statfs.h>
  59. #  define STATFS statfs
  60. #  define F_BSIZE f_bsize
  61. #  ifdef __MINT__                /* do we still need this? */
  62. #   define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
  63. #  endif
  64. # endif
  65. #endif
  66.  
  67. /*
  68.  * for Amiga Dos 2.0x we use Flush
  69.  */
  70. #ifdef AMIGA
  71. # ifndef NO_ARP
  72. extern int dos2;                        /* this is in amiga.c */
  73. # endif
  74. # ifdef SASC
  75. #  include <proto/dos.h>
  76. #  include <ios1.h>                        /* for chkufb() */
  77. # endif
  78. #endif
  79.  
  80. #define MEMFILE_PAGE_SIZE 4096            /* default page size */
  81.  
  82. static long total_mem_used = 0;            /* total memory used for memfiles */
  83.  
  84. static void mf_ins_hash __ARGS((MEMFILE *, BHDR *));
  85. static void mf_rem_hash __ARGS((MEMFILE *, BHDR *));
  86. static BHDR *mf_find_hash __ARGS((MEMFILE *, blocknr_t));
  87. static void mf_ins_used __ARGS((MEMFILE *, BHDR *));
  88. static void mf_rem_used __ARGS((MEMFILE *, BHDR *));
  89. static BHDR *mf_release __ARGS((MEMFILE *, int));
  90. static BHDR *mf_alloc_bhdr __ARGS((MEMFILE *, int));
  91. static void mf_free_bhdr __ARGS((BHDR *));
  92. static void mf_ins_free __ARGS((MEMFILE *, BHDR *));
  93. static BHDR *mf_rem_free __ARGS((MEMFILE *));
  94. static int    mf_read __ARGS((MEMFILE *, BHDR *));
  95. static int    mf_write __ARGS((MEMFILE *, BHDR *));
  96. static int    mf_trans_add __ARGS((MEMFILE *, BHDR *));
  97. static void mf_do_open __ARGS((MEMFILE *, char_u *, int));
  98.  
  99. /*
  100.  * The functions for using a memfile:
  101.  *
  102.  * mf_open()        open a new or existing memfile
  103.  * mf_open_file()    open a swap file for an existing memfile
  104.  * mf_close()        close (and delete) a memfile
  105.  * mf_new()            create a new block in a memfile and lock it
  106.  * mf_get()            get an existing block and lock it
  107.  * mf_put()            unlock a block, may be marked for writing
  108.  * mf_free()        remove a block
  109.  * mf_sync()        sync changed parts of memfile to disk
  110.  * mf_release_all()    release as much memory as possible
  111.  * mf_trans_del()    may translate negative to positive block number
  112.  * mf_fullname()    make file name full path (use before first :cd)
  113.  */
  114.  
  115. /*
  116.  * mf_open: open an existing or new memory block file
  117.  *
  118.  *    fname:        name of file to use (NULL means no file at all)
  119.  *                Note: fname must have been allocated, it is not copied!
  120.  *                        If opening the file fails, fname is NOT freed.
  121.  *  trunc_file:        if TRUE: file should be truncated when opening
  122.  *
  123.  *  If fname != NULL and file cannot be opened, fail.
  124.  *
  125.  * return value: identifier for this memory block file.
  126.  */
  127.     MEMFILE *
  128. mf_open(fname, trunc_file)
  129.     char_u    *fname;
  130.     int        trunc_file;
  131. {
  132.     MEMFILE            *mfp;
  133.     int                i;
  134.     off_t            size;
  135. #if defined(STATFS) && defined(UNIX) && !defined(__QNX__)
  136. # define USE_FSTATFS
  137.     struct STATFS     stf;
  138. #endif
  139.  
  140.     if ((mfp = (MEMFILE *)alloc((unsigned)sizeof(MEMFILE))) == NULL)
  141.         return NULL;
  142.  
  143.     if (fname == NULL)        /* no file for this memfile, use memory only */
  144.     {
  145.         mfp->mf_fname = NULL;
  146.         mfp->mf_xfname = NULL;
  147.         mfp->mf_fd = -1;
  148.     }
  149.     else
  150.     {
  151.         mf_do_open(mfp, fname, trunc_file);        /* try to open the file */
  152.  
  153.         /* if the file cannot be opened, return here */
  154.         if (mfp->mf_fd < 0)
  155.         {
  156.             vim_free(mfp);
  157.             return NULL;
  158.         }
  159.     }
  160.  
  161.     mfp->mf_free_first = NULL;            /* free list is empty */
  162.     mfp->mf_used_first = NULL;            /* used list is empty */
  163.     mfp->mf_used_last = NULL;
  164.     mfp->mf_dirty = FALSE;
  165.     mfp->mf_used_count = 0;
  166.     for (i = 0; i < MEMHASHSIZE; ++i)
  167.     {
  168.         mfp->mf_hash[i] = NULL;            /* hash lists are empty */
  169.         mfp->mf_trans[i] = NULL;        /* trans lists are empty */
  170.     }
  171.     mfp->mf_page_size = MEMFILE_PAGE_SIZE;
  172.  
  173. #ifdef USE_FSTATFS
  174.     /*
  175.      * Try to set the page size equal to the block size of the device.
  176.      * Speeds up I/O a lot.
  177.      * NOTE: minimal block size depends on size of block 0 data! It's not done
  178.      * with a sizeof(), because block 0 is defined in memline.c (Sorry).
  179.      * The maximal block size is arbitrary.
  180.      */
  181.     if (mfp->mf_fd >= 0 &&
  182.                     fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0 &&
  183.                     stf.F_BSIZE >= 1048 && stf.F_BSIZE <= 50000)
  184.         mfp->mf_page_size = stf.F_BSIZE;
  185. #endif
  186.  
  187.     if (mfp->mf_fd < 0 || trunc_file ||
  188.                                 (size = lseek(mfp->mf_fd, 0L, SEEK_END)) <= 0)
  189.         mfp->mf_blocknr_max = 0;        /* no file or empty file */
  190.     else
  191.         mfp->mf_blocknr_max = size / mfp->mf_page_size;
  192.     mfp->mf_blocknr_min = -1;
  193.     mfp->mf_neg_count = 0;
  194.     mfp->mf_infile_count = mfp->mf_blocknr_max;
  195.     if (mfp->mf_fd < 0)
  196.         mfp->mf_used_count_max = 0;            /* no limit */
  197.     else
  198.         mfp->mf_used_count_max = p_mm * 1024 / mfp->mf_page_size;
  199.  
  200.     return mfp;
  201. }
  202.  
  203. /*
  204.  * mf_open_file: open a file for an existing memfile. Used when updatecount
  205.  *                 set from 0 to some value.
  206.  *
  207.  *    fname:        name of file to use (NULL means no file at all)
  208.  *                Note: fname must have been allocated, it is not copied!
  209.  *                        If opening the file fails, fname is NOT freed.
  210.  *
  211.  * return value: FAIL if file could not be opened, OK otherwise
  212.  */
  213.     int
  214. mf_open_file(mfp, fname)
  215.     MEMFILE        *mfp;
  216.     char_u        *fname;
  217. {
  218.     mf_do_open(mfp, fname, TRUE);                /* try to open the file */
  219.  
  220.     if (mfp->mf_fd < 0)
  221.         return FAIL;
  222.  
  223.     mfp->mf_dirty = TRUE;
  224.     return OK;
  225. }
  226.  
  227. /*
  228.  * close a memory file and delete the associated file if 'del_file' is TRUE
  229.  */
  230.     void
  231. mf_close(mfp, del_file)
  232.     MEMFILE    *mfp;
  233.     int        del_file;
  234. {
  235.     BHDR        *hp, *nextp;
  236.     NR_TRANS    *tp, *tpnext;
  237.     int            i;
  238.  
  239.     if (mfp == NULL)                /* safety check */
  240.         return;
  241.     if (mfp->mf_fd >= 0)
  242.     {
  243.         if (close(mfp->mf_fd) < 0)
  244.             EMSG("Close error on swap file");
  245.     }
  246.     if (del_file && mfp->mf_fname != NULL)
  247.         vim_remove(mfp->mf_fname);
  248.                                             /* free entries in used list */
  249.     for (hp = mfp->mf_used_first; hp != NULL; hp = nextp)
  250.     {
  251.         total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
  252.         nextp = hp->bh_next;
  253.         mf_free_bhdr(hp);
  254.     }
  255.     while (mfp->mf_free_first != NULL)        /* free entries in free list */
  256.         vim_free(mf_rem_free(mfp));
  257.     for (i = 0; i < MEMHASHSIZE; ++i)        /* free entries in trans lists */
  258.         for (tp = mfp->mf_trans[i]; tp != NULL; tp = tpnext)
  259.         {
  260.             tpnext = tp->nt_next;
  261.             vim_free(tp);
  262.         }
  263.     vim_free(mfp->mf_fname);
  264.     vim_free(mfp->mf_xfname);
  265.     vim_free(mfp);
  266. }
  267.  
  268. /*
  269.  * get a new block
  270.  *
  271.  *   negative: TRUE if negative block number desired (data block)
  272.  */
  273.     BHDR *
  274. mf_new(mfp, negative, page_count)
  275.     MEMFILE        *mfp;
  276.     int            negative;
  277.     int            page_count;
  278. {
  279.     BHDR    *hp;            /* new BHDR */
  280.     BHDR    *freep;            /* first block in free list */
  281.     char_u    *p;
  282.  
  283.     /*
  284.      * If we reached the maximum size for the used memory blocks, release one
  285.      * If a BHDR is returned, use it and adjust the page_count if necessary.
  286.      */
  287.     hp = mf_release(mfp, page_count);
  288.  
  289. /*
  290.  * Decide on the number to use:
  291.  * If there is a free block, use its number.
  292.  * Otherwise use mf_block_min for a negative number, mf_block_max for
  293.  * a positive number.
  294.  */
  295.     freep = mfp->mf_free_first;
  296.     if (!negative && freep != NULL && freep->bh_page_count >= page_count)
  297.     {
  298.         /*
  299.          * If the block in the free list has more pages, take only the number
  300.          * of pages needed and allocate a new BHDR with data
  301.          *
  302.          * If the number of pages matches and mf_release did not return a BHDR,
  303.          * use the BHDR from the free list and allocate the data
  304.          *
  305.          * If the number of pages matches and mf_release returned a BHDR,
  306.          * just use the number and free the BHDR from the free list
  307.          */
  308.         if (freep->bh_page_count > page_count)
  309.         {
  310.             if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  311.                 return NULL;
  312.             hp->bh_bnum = freep->bh_bnum;
  313.             freep->bh_bnum += page_count;
  314.             freep->bh_page_count -= page_count;
  315.         }
  316.         else if (hp == NULL)        /* need to allocate memory for this block */
  317.         {
  318.             if ((p = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL)
  319.                 return NULL;
  320.             hp = mf_rem_free(mfp);
  321.             hp->bh_data = p;
  322.         }
  323.         else                /* use the number, remove entry from free list */
  324.         {
  325.             freep = mf_rem_free(mfp);
  326.             hp->bh_bnum = freep->bh_bnum;
  327.             vim_free(freep);
  328.         }
  329.     }
  330.     else        /* get a new number */
  331.     {
  332.         if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  333.             return NULL;
  334.         if (negative)
  335.         {
  336.             hp->bh_bnum = mfp->mf_blocknr_min--;
  337.             mfp->mf_neg_count++;
  338.         }
  339.         else
  340.         {
  341.             hp->bh_bnum = mfp->mf_blocknr_max;
  342.             mfp->mf_blocknr_max += page_count;
  343.         }
  344.     }
  345.     hp->bh_flags = BH_LOCKED | BH_DIRTY;        /* new block is always dirty */
  346.     mfp->mf_dirty = TRUE;
  347.     hp->bh_page_count = page_count;
  348.     mf_ins_used(mfp, hp);
  349.     mf_ins_hash(mfp, hp);
  350.  
  351.     /*
  352.      * Init the data to all zero, to avoid reading uninitialized data.
  353.      * This also avoids that the passwd file ends up in the swap file!
  354.      */
  355.     (void)vim_memset((char *)(hp->bh_data), 0, (size_t)mfp->mf_page_size);
  356.  
  357.     return hp;
  358. }
  359.  
  360. /*
  361.  * get existing block 'nr' with 'page_count' pages
  362.  *
  363.  * Note: The caller should first check a negative nr with mf_trans_del()
  364.  */
  365.     BHDR *
  366. mf_get(mfp, nr, page_count)
  367.     MEMFILE        *mfp;
  368.     blocknr_t    nr;
  369.     int            page_count;
  370. {
  371.     BHDR    *hp;
  372.                                                 /* doesn't exist */
  373.     if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min)
  374.         return NULL;
  375.  
  376.     /*
  377.      * see if it is in the cache
  378.      */
  379.     hp = mf_find_hash(mfp, nr);
  380.     if (hp == NULL)        /* not in the hash list */
  381.     {
  382.         if (nr < 0 || nr >= mfp->mf_infile_count)    /* can't be in the file */
  383.             return NULL;
  384.  
  385.         /* could check here if the block is in the free list */
  386.  
  387.         /*
  388.          * Check if we need to flush an existing block.
  389.          * If so, use that block.
  390.          * If not, allocate a new block.
  391.          */
  392.         hp = mf_release(mfp, page_count);
  393.         if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  394.             return NULL;
  395.  
  396.         hp->bh_bnum = nr;
  397.         hp->bh_flags = 0;
  398.         hp->bh_page_count = page_count;
  399.         if (mf_read(mfp, hp) == FAIL)        /* cannot read the block! */
  400.         {
  401.             mf_free_bhdr(hp);
  402.             return NULL;
  403.         }
  404.     }
  405.     else
  406.     {
  407.         mf_rem_used(mfp, hp);    /* remove from list, insert in front below */
  408.         mf_rem_hash(mfp, hp);
  409.     }
  410.  
  411.     hp->bh_flags |= BH_LOCKED;
  412.     mf_ins_used(mfp, hp);        /* put in front of used list */
  413.     mf_ins_hash(mfp, hp);        /* put in front of hash list */
  414.  
  415.     return hp;
  416. }
  417.  
  418. /*
  419.  * release the block *hp
  420.  *
  421.  *   dirty: Block must be written to file later
  422.  *     infile: Block should be in file (needed for recovery)
  423.  *
  424.  *  no return value, function cannot fail
  425.  */
  426.     void
  427. mf_put(mfp, hp, dirty, infile)
  428.     MEMFILE    *mfp;
  429.     BHDR    *hp;
  430.     int        dirty;
  431.     int        infile;
  432. {
  433.     int        flags;
  434.  
  435.     flags = hp->bh_flags;
  436.     CHECK((flags & BH_LOCKED) == 0, "block was not locked");
  437.     flags &= ~BH_LOCKED;
  438.     if (dirty)
  439.     {
  440.         flags |= BH_DIRTY;
  441.         mfp->mf_dirty = TRUE;
  442.     }
  443.     hp->bh_flags = flags;
  444.     if (infile)
  445.         mf_trans_add(mfp, hp);        /* may translate negative in positive nr */
  446. }
  447.  
  448. /*
  449.  * block *hp is no longer in used, may put it in the free list of memfile *mfp
  450.  */
  451.     void
  452. mf_free(mfp, hp)
  453.     MEMFILE    *mfp;
  454.     BHDR    *hp;
  455. {
  456.     vim_free(hp->bh_data);        /* free the memory */
  457.     mf_rem_hash(mfp, hp);        /* get *hp out of the hash list */
  458.     mf_rem_used(mfp, hp);        /* get *hp out of the used list */
  459.     if (hp->bh_bnum < 0)
  460.     {
  461.         vim_free(hp);            /* don't want negative numbers in free list */
  462.         mfp->mf_neg_count--;
  463.     }
  464.     else
  465.         mf_ins_free(mfp, hp);    /* put *hp in the free list */
  466. }
  467.  
  468. /*
  469.  * sync the memory file *mfp to disk
  470.  *    if 'all' is FALSE blocks with negative numbers are not synced, even when
  471.  *  they are dirty!
  472.  *  if 'check_char' is TRUE, stop syncing when a character becomes available,
  473.  *  but sync at least one block.
  474.  *  if 'do_fsync' is TRUE make sure buffers are flushed to disk, so they will
  475.  *  survive a system crash.
  476.  *
  477.  * Return FAIL for failure, OK otherwise
  478.  */
  479.     int
  480. mf_sync(mfp, all, check_char, do_fsync)
  481.     MEMFILE    *mfp;
  482.     int        all;
  483.     int        check_char;
  484.     int        do_fsync;
  485. {
  486.     int        status;
  487.     BHDR    *hp;
  488. #ifdef SYNC_DUP_CLOSE
  489.     int        fd;
  490. #endif
  491.  
  492.     if (mfp->mf_fd < 0)        /* there is no file, nothing to do */
  493.     {
  494.         mfp->mf_dirty = FALSE;
  495.         return FAIL;
  496.     }
  497.  
  498.     /*
  499.      * sync from last to first (may reduce the probability of an inconsistent
  500.      * file) If a write fails, it is very likely caused by a full filesystem.
  501.      * Then we only try to write blocks within the existing file. If that also
  502.      * fails then we give up.
  503.      */
  504.     status = OK;
  505.     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  506.         if ((all || hp->bh_bnum >= 0) && (hp->bh_flags & BH_DIRTY) &&
  507.                     (status == OK || (hp->bh_bnum >= 0 &&
  508.                         hp->bh_bnum < mfp->mf_infile_count)))
  509.         {
  510.             if (mf_write(mfp, hp) == FAIL)
  511.             {
  512.                 if (status == FAIL)        /* double error: quit syncing */
  513.                     break;
  514.                 status = FAIL;
  515.             }
  516.             if (check_char && mch_char_avail())    /* char available now */
  517.                 break;
  518.         }
  519.     
  520.     /*
  521.      * If the whole list is flushed, the memfile is not dirty anymore.
  522.      * In case of an error this flag is also set, to avoid trying all the time.
  523.      */
  524.     if (hp == NULL || status == FAIL)
  525.         mfp->mf_dirty = FALSE;
  526.  
  527.     if (do_fsync && *p_sws != NUL)
  528.     {
  529. #if defined(UNIX)
  530. # ifdef HAVE_FSYNC
  531.         /*
  532.          * most Unixes have the very useful fsync() function, just what we need.
  533.          * However, with OS/2 and EMX it is also available, but there are
  534.          * reports of bad problems with it (a bug in HPFS.IFS).
  535.          * So we disable use of it here in case someone tries to be smart
  536.          * and changes conf_os2.h... (even though there is no __EMX__ test
  537.          * in the #if, as __EMX__ does not have sync(); we hope for a timely
  538.          * sync from the system itself).
  539.          */
  540. #  if defined(__EMX__)
  541.    error "Dont use fsync with EMX! Read emxdoc.doc or emxfix01.doc for info."
  542. #  endif
  543.         if (STRCMP(p_sws, "fsync") == 0)
  544.         {
  545.             if (fsync(mfp->mf_fd))
  546.                 status = FAIL;
  547.         }
  548.         else
  549. # endif
  550.              sync();
  551. #endif
  552. #ifdef DJGPP
  553.         if (_dos_commit(mfp->mf_fd))
  554.             status = FAIL;
  555. #else
  556. # ifdef SYNC_DUP_CLOSE
  557.         /*
  558.          * MSdos is a bit more work: Duplicate the file handle and close it.
  559.          * This should flush the file to disk.
  560.          */
  561.         if ((fd = dup(mfp->mf_fd)) >= 0)
  562.             close(fd);
  563. # endif
  564. #endif
  565. #ifdef AMIGA
  566.         /*
  567.          * Flush() only exists for AmigaDos 2.0.
  568.          * For 1.3 it should be done with close() + open(), but then the risk
  569.          * is that the open() may fail and lose the file....
  570.          */
  571. # ifndef NO_ARP
  572.         if (dos2)
  573. # endif
  574. # ifdef SASC
  575.         {
  576.             struct UFB *fp = chkufb(mfp->mf_fd);
  577.  
  578.             if (fp != NULL)
  579.                 Flush(fp->ufbfh);
  580.         }
  581. # else
  582. #  ifdef _DCC
  583.         {
  584.             BPTR fh = (BPTR)fdtofh(mfp->mf_fd);
  585.  
  586.             if (fh != 0)
  587.                 Flush(fh);
  588.             }
  589. #  else /* assume Manx */
  590.             Flush(_devtab[mfp->mf_fd].fd);
  591. #  endif
  592. # endif
  593. #endif /* AMIGA */
  594.     }
  595.  
  596.     return status;
  597. }
  598.  
  599. /*
  600.  * insert block *hp in front of hashlist of memfile *mfp
  601.  */
  602.     static void
  603. mf_ins_hash(mfp, hp)
  604.     MEMFILE    *mfp;
  605.     BHDR    *hp;
  606. {
  607.     BHDR    *hhp;
  608.     int        hash;
  609.  
  610.     hash = MEMHASH(hp->bh_bnum);
  611.     hhp = mfp->mf_hash[hash];
  612.     hp->bh_hash_next = hhp;
  613.     hp->bh_hash_prev = NULL;
  614.     if (hhp != NULL)
  615.         hhp->bh_hash_prev = hp;
  616.     mfp->mf_hash[hash] = hp;
  617. }
  618.  
  619. /*
  620.  * remove block *hp from hashlist of memfile list *mfp
  621.  */
  622.     static void
  623. mf_rem_hash(mfp, hp)
  624.     MEMFILE    *mfp;
  625.     BHDR    *hp;
  626. {
  627.     if (hp->bh_hash_prev == NULL)
  628.         mfp->mf_hash[MEMHASH(hp->bh_bnum)] = hp->bh_hash_next;
  629.     else
  630.         hp->bh_hash_prev->bh_hash_next = hp->bh_hash_next;
  631.     
  632.     if (hp->bh_hash_next)
  633.         hp->bh_hash_next->bh_hash_prev = hp->bh_hash_prev;
  634. }
  635.  
  636. /*
  637.  * look in hash lists of memfile *mfp for block header with number 'nr'
  638.  */
  639.     static BHDR *
  640. mf_find_hash(mfp, nr)
  641.     MEMFILE        *mfp;
  642.     blocknr_t    nr;
  643. {
  644.     BHDR        *hp;
  645.  
  646.     for (hp = mfp->mf_hash[MEMHASH(nr)]; hp != NULL; hp = hp->bh_hash_next)
  647.         if (hp->bh_bnum == nr)
  648.             break;
  649.     return hp;
  650. }
  651.  
  652. /*
  653.  * insert block *hp in front of used list of memfile *mfp
  654.  */
  655.     static void
  656. mf_ins_used(mfp, hp)
  657.     MEMFILE    *mfp;
  658.     BHDR    *hp;
  659. {
  660.     hp->bh_next = mfp->mf_used_first;
  661.     mfp->mf_used_first = hp;
  662.     hp->bh_prev = NULL;
  663.     if (hp->bh_next == NULL)        /* list was empty, adjust last pointer */
  664.         mfp->mf_used_last = hp;
  665.     else
  666.         hp->bh_next->bh_prev = hp;
  667.     mfp->mf_used_count += hp->bh_page_count;
  668.     total_mem_used += hp->bh_page_count * mfp->mf_page_size;
  669. }
  670.  
  671. /*
  672.  * remove block *hp from used list of memfile *mfp
  673.  */
  674.     static void
  675. mf_rem_used(mfp, hp)
  676.     MEMFILE    *mfp;
  677.     BHDR    *hp;
  678. {
  679.     if (hp->bh_next == NULL)        /* last block in used list */
  680.         mfp->mf_used_last = hp->bh_prev;
  681.     else
  682.         hp->bh_next->bh_prev = hp->bh_prev;
  683.     if (hp->bh_prev == NULL)        /* first block in used list */
  684.         mfp->mf_used_first = hp->bh_next;
  685.     else
  686.         hp->bh_prev->bh_next = hp->bh_next;
  687.     mfp->mf_used_count -= hp->bh_page_count;
  688.     total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
  689. }
  690.  
  691. /*
  692.  * Release the least recently used block from the used list if the number
  693.  * of used memory blocks gets to big.
  694.  *
  695.  * Return the block header to the caller, including the memory block, so
  696.  * it can be re-used. Make sure the page_count is right.
  697.  */
  698.     static BHDR *
  699. mf_release(mfp, page_count)
  700.     MEMFILE        *mfp;
  701.     int            page_count;
  702. {
  703.     BHDR        *hp;
  704.  
  705.         /*
  706.          * don't release a block if
  707.          *        there is no file for this memfile
  708.          * or
  709.          *         there is no limit to the number of blocks for this memfile or
  710.          *        the maximum is not reached yet
  711.          *    and
  712.          *        total memory used is not up to 'maxmemtot'
  713.          */
  714.     if (mfp->mf_fd < 0 || ((mfp->mf_used_count < mfp->mf_used_count_max ||
  715.                         mfp->mf_used_count_max == 0) &&
  716.                         (total_mem_used >> 10) < p_mmt))
  717.         return NULL;
  718.  
  719.     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  720.         if (!(hp->bh_flags & BH_LOCKED))
  721.             break;
  722.     if (hp == NULL)        /* not a single one that can be released */
  723.         return NULL;
  724.  
  725.         /*
  726.          * If the block is dirty, write it.
  727.          * If the write fails we don't free it.
  728.          */
  729.     if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
  730.         return NULL;
  731.  
  732.     mf_rem_used(mfp, hp);
  733.     mf_rem_hash(mfp, hp);
  734.  
  735. /*
  736.  * If a BHDR is returned, make sure that the page_count of bh_data is right
  737.  */
  738.     if (hp->bh_page_count != page_count)
  739.     {
  740.         vim_free(hp->bh_data);
  741.         if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
  742.         {
  743.             vim_free(hp);
  744.             return NULL;
  745.         }
  746.         hp->bh_page_count = page_count;
  747.     }
  748.     return hp;
  749. }
  750.  
  751. /*
  752.  * release as many blocks as possible
  753.  * Used in case of out of memory
  754.  *
  755.  * return TRUE if any memory was released
  756.  */
  757.     int
  758. mf_release_all()
  759. {
  760.     BUF            *buf;
  761.     MEMFILE        *mfp;
  762.     BHDR        *hp;
  763.     int            retval = FALSE;
  764.  
  765.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  766.     {
  767.         mfp = buf->b_ml.ml_mfp;
  768.         if (mfp != NULL && mfp->mf_fd >= 0)        /* only if there is a memfile with a file */
  769.             for (hp = mfp->mf_used_last; hp != NULL; )
  770.             {
  771.                 if (!(hp->bh_flags & BH_LOCKED) &&
  772.                         (!(hp->bh_flags & BH_DIRTY) || mf_write(mfp, hp) != FAIL))
  773.                 {
  774.                     mf_rem_used(mfp, hp);
  775.                     mf_rem_hash(mfp, hp);
  776.                     mf_free_bhdr(hp);
  777.                     hp = mfp->mf_used_last;        /* re-start, list was changed */
  778.                     retval = TRUE;
  779.                 }
  780.                 else
  781.                     hp = hp->bh_prev;
  782.             }
  783.     }
  784.     return retval;
  785. }
  786.  
  787. /*
  788.  * Allocate a block header and a block of memory for it
  789.  */
  790.     static BHDR *
  791. mf_alloc_bhdr(mfp, page_count)
  792.     MEMFILE        *mfp;
  793.     int            page_count;
  794. {
  795.     BHDR    *hp;
  796.  
  797.     if ((hp = (BHDR *)alloc((unsigned)sizeof(BHDR))) != NULL)
  798.     {
  799.         if ((hp->bh_data = (char_u *)alloc(mfp->mf_page_size * page_count))
  800.                                                                       == NULL)
  801.         {
  802.             vim_free(hp);            /* not enough memory */
  803.             return NULL;
  804.         }
  805.         hp->bh_page_count = page_count;
  806.     }
  807.     return hp;
  808. }
  809.  
  810. /*
  811.  * Free a block header and the block of memory for it
  812.  */
  813.     static void
  814. mf_free_bhdr(hp)
  815.     BHDR        *hp;
  816. {
  817.     vim_free(hp->bh_data);
  818.     vim_free(hp);
  819. }
  820.  
  821. /*
  822.  * insert entry *hp in the free list
  823.  */
  824.     static void
  825. mf_ins_free(mfp, hp)
  826.     MEMFILE    *mfp;
  827.     BHDR    *hp;
  828. {
  829.     hp->bh_next = mfp->mf_free_first;
  830.     mfp->mf_free_first = hp;
  831. }
  832.  
  833. /*
  834.  * remove the first entry from the free list and return a pointer to it
  835.  * Note: caller must check that mfp->mf_free_first is not NULL!
  836.  */
  837.     static BHDR *
  838. mf_rem_free(mfp)
  839.     MEMFILE    *mfp;
  840. {
  841.     BHDR    *hp;
  842.  
  843.     hp = mfp->mf_free_first;
  844.     mfp->mf_free_first = hp->bh_next;
  845.     return hp;
  846. }
  847.  
  848. /*
  849.  * read a block from disk
  850.  * 
  851.  * Return FAIL for failure, OK otherwise
  852.  */
  853.     static int
  854. mf_read(mfp, hp)
  855.     MEMFILE        *mfp;
  856.     BHDR        *hp;
  857. {
  858.     off_t        offset;
  859.     unsigned    page_size;
  860.     unsigned    size;
  861.  
  862.     if (mfp->mf_fd < 0)        /* there is no file, can't read */
  863.         return FAIL;
  864.  
  865.     page_size = mfp->mf_page_size;
  866.     offset = page_size * hp->bh_bnum;
  867.     size = page_size * hp->bh_page_count;
  868.     if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
  869.     {
  870.         EMSG("Seek error in swap file read");
  871.         return FAIL;
  872.     }
  873.     if ((unsigned)read(mfp->mf_fd, (char *)hp->bh_data, (size_t)size) != size)
  874.     {
  875.         EMSG("Read error in swap file");
  876.         return FAIL;
  877.     }
  878.     return OK;
  879. }
  880.  
  881. /*
  882.  * write a block to disk
  883.  * 
  884.  * Return FAIL for failure, OK otherwise
  885.  */
  886.     static int
  887. mf_write(mfp, hp)
  888.     MEMFILE        *mfp;
  889.     BHDR        *hp;
  890. {
  891.     off_t        offset;        /* offset in the file */
  892.     blocknr_t    nr;            /* block nr which is being written */
  893.     BHDR        *hp2;
  894.     unsigned    page_size;    /* number of bytes in a page */
  895.     unsigned    page_count;    /* number of pages written */
  896.     unsigned    size;        /* number of bytes written */
  897.  
  898.     if (mfp->mf_fd < 0)        /* there is no file, can't write */
  899.         return FAIL;
  900.  
  901.     if (hp->bh_bnum < 0)        /* must assign file block number */
  902.         if (mf_trans_add(mfp, hp) == FAIL)
  903.             return FAIL;
  904.  
  905.     page_size = mfp->mf_page_size;
  906.  
  907.     /*
  908.      * We don't want gaps in the file. Write the blocks in front of *hp
  909.      * to extend the file.
  910.      * If block 'mf_infile_count' is not in the hash list, it has been
  911.      * freed. Fill the space in the file with data from the current block.
  912.      */
  913.     for (;;)
  914.     {
  915.         nr = hp->bh_bnum;
  916.         if (nr > mfp->mf_infile_count)            /* beyond end of file */
  917.         {
  918.             nr = mfp->mf_infile_count;
  919.             hp2 = mf_find_hash(mfp, nr);        /* NULL catched below */
  920.         }
  921.         else
  922.             hp2 = hp;
  923.  
  924.         offset = page_size * nr;
  925.         if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
  926.         {
  927.             EMSG("Seek error in swap file write");
  928.             return FAIL;
  929.         }
  930.         if (hp2 == NULL)            /* freed block, fill with dummy data */
  931.             page_count = 1;
  932.         else
  933.             page_count = hp2->bh_page_count;
  934.         size = page_size * page_count;
  935.         if ((unsigned)write(mfp->mf_fd,
  936.              (char *)(hp2 == NULL ? hp : hp2)->bh_data, (size_t)size) != size)
  937.         {
  938.             /*
  939.              * Avoid repeating the error message, this mostly happens when the
  940.              * disk is full. We give the message again only after a succesful
  941.              * write or when hitting a key. We keep on trying, in case some
  942.              * space becomes available.
  943.              */
  944.             if (!did_swapwrite_msg)
  945.                 EMSG("Write error in swap file");
  946.             did_swapwrite_msg = TRUE;
  947.             return FAIL;
  948.         }
  949.         did_swapwrite_msg = FALSE;
  950.         if (hp2 != NULL)                    /* written a non-dummy block */
  951.             hp2->bh_flags &= ~BH_DIRTY;
  952.                                             /* appended to the file */
  953.         if (nr + (blocknr_t)page_count > mfp->mf_infile_count)
  954.             mfp->mf_infile_count = nr + page_count;
  955.         if (nr == hp->bh_bnum)                /* written the desired block */
  956.             break;
  957.     }
  958.     return OK;
  959. }
  960.  
  961. /*
  962.  * Make block number for *hp positive and add it to the translation list
  963.  * 
  964.  * Return FAIL for failure, OK otherwise
  965.  */
  966.     static int
  967. mf_trans_add(mfp, hp)
  968.     MEMFILE    *mfp;
  969.     BHDR    *hp;
  970. {
  971.     BHDR        *freep;
  972.     blocknr_t    new_bnum;
  973.     int            hash;
  974.     NR_TRANS    *np;
  975.     int            page_count;
  976.  
  977.     if (hp->bh_bnum >= 0)                    /* it's already positive */
  978.         return OK;
  979.  
  980.     if ((np = (NR_TRANS *)alloc((unsigned)sizeof(NR_TRANS))) == NULL)
  981.         return FAIL;
  982.  
  983. /*
  984.  * get a new number for the block.
  985.  * If the first item in the free list has sufficient pages, use its number
  986.  * Otherwise use mf_blocknr_max.
  987.  */
  988.     freep = mfp->mf_free_first;
  989.     page_count = hp->bh_page_count;
  990.     if (freep != NULL && freep->bh_page_count >= page_count)
  991.     {
  992.         new_bnum = freep->bh_bnum;
  993.         /*
  994.          * If the page count of the free block was larger, recude it.
  995.          * If the page count matches, remove the block from the free list
  996.          */
  997.         if (freep->bh_page_count > page_count)
  998.         {
  999.             freep->bh_bnum += page_count;
  1000.             freep->bh_page_count -= page_count;
  1001.         }
  1002.         else
  1003.         {
  1004.             freep = mf_rem_free(mfp);
  1005.             vim_free(freep);
  1006.         }
  1007.     }
  1008.     else
  1009.     {
  1010.         new_bnum = mfp->mf_blocknr_max;
  1011.         mfp->mf_blocknr_max += page_count;
  1012.     }
  1013.  
  1014.     np->nt_old_bnum = hp->bh_bnum;            /* adjust number */
  1015.     np->nt_new_bnum = new_bnum;
  1016.  
  1017.     mf_rem_hash(mfp, hp);                    /* remove from old hash list */
  1018.     hp->bh_bnum = new_bnum;
  1019.     mf_ins_hash(mfp, hp);                    /* insert in new hash list */
  1020.  
  1021.     hash = MEMHASH(np->nt_old_bnum);        /* insert in trans list */
  1022.     np->nt_next = mfp->mf_trans[hash];
  1023.     mfp->mf_trans[hash] = np;
  1024.     if (np->nt_next != NULL)
  1025.         np->nt_next->nt_prev = np;
  1026.     np->nt_prev = NULL;    
  1027.  
  1028.     return OK;
  1029. }
  1030.  
  1031. /*
  1032.  * Lookup a tranlation from the trans lists and delete the entry
  1033.  * 
  1034.  * Return the positive new number when found, the old number when not found
  1035.  */
  1036.      blocknr_t
  1037. mf_trans_del(mfp, old_nr)
  1038.     MEMFILE        *mfp;
  1039.     blocknr_t    old_nr;
  1040. {
  1041.     int            hash;
  1042.     NR_TRANS    *np;
  1043.     blocknr_t    new_bnum;
  1044.  
  1045.     hash = MEMHASH(old_nr);
  1046.     for (np = mfp->mf_trans[hash]; np != NULL; np = np->nt_next)
  1047.         if (np->nt_old_bnum == old_nr)
  1048.             break;
  1049.     if (np == NULL)                /* not found */
  1050.         return old_nr;
  1051.  
  1052.     mfp->mf_neg_count--;
  1053.     new_bnum = np->nt_new_bnum;
  1054.     if (np->nt_prev != NULL)            /* remove entry from the trans list */
  1055.         np->nt_prev->nt_next = np->nt_next;
  1056.     else
  1057.         mfp->mf_trans[hash] = np->nt_next;
  1058.     if (np->nt_next != NULL)
  1059.         np->nt_next->nt_prev = np->nt_prev;
  1060.     vim_free(np);
  1061.  
  1062.     return new_bnum;
  1063. }
  1064.  
  1065. /*
  1066.  * Set mfp->mf_xfname according to mfp->mf_fname and some other things.
  1067.  * Don't get the full path name if did_cd is TRUE, then fname should
  1068.  * already be a full path name.
  1069.  */
  1070.     void
  1071. mf_set_xfname(mfp)
  1072.     MEMFILE        *mfp;
  1073. {
  1074.     mfp->mf_xfname = NULL;
  1075.     if (!did_cd)
  1076.         mfp->mf_xfname = FullName_save(mfp->mf_fname);
  1077. }
  1078.  
  1079. /*
  1080.  * Make the name of the file used for the memfile a full path.
  1081.  * Used before doing a :cd
  1082.  */
  1083.     void
  1084. mf_fullname(mfp)
  1085.     MEMFILE        *mfp;
  1086. {
  1087.     if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_xfname != NULL)
  1088.     {
  1089.         vim_free(mfp->mf_fname);
  1090.         mfp->mf_fname = mfp->mf_xfname;
  1091.         mfp->mf_xfname = NULL;
  1092.     }
  1093. }
  1094.  
  1095. /*
  1096.  * return TRUE if there are any translations pending for 'mfp'
  1097.  */
  1098.     int
  1099. mf_need_trans(mfp)
  1100.     MEMFILE        *mfp;
  1101. {
  1102.     return (mfp->mf_fname != NULL && mfp->mf_neg_count > 0);
  1103. }
  1104.  
  1105. #if 0            /* included for beta testing only */
  1106. /*
  1107.  * print statistics for a memfile (for debugging)
  1108.  */
  1109.     void
  1110. mf_statistics()
  1111. {
  1112.     MEMFILE        *mfp;
  1113.     BHDR        *hp;
  1114.     int            used = 0;
  1115.     int            locked = 0;
  1116.     int            dirty = 0;
  1117.     int            nfree = 0;
  1118.     int            negative = 0;
  1119.  
  1120.     mfp = curbuf->b_ml.ml_mfp;
  1121.     if (mfp == NULL)
  1122.         MSG("No memfile");
  1123.     else
  1124.     {
  1125.         for (hp = mfp->mf_used_first; hp != NULL; hp = hp->bh_next)
  1126.         {
  1127.             ++used;
  1128.             if (hp->bh_flags & BH_LOCKED)
  1129.                 ++locked;
  1130.             if (hp->bh_flags & BH_DIRTY)
  1131.                 ++dirty;
  1132.             if (hp->bh_bnum < 0)
  1133.                 ++negative;
  1134.         }
  1135.         for (hp = mfp->mf_free_first; hp != NULL; hp = hp->bh_next)
  1136.             ++nfree;
  1137.         sprintf((char *)IObuff, "%d used (%d locked, %d dirty, %d (%d) negative), %d free",
  1138.                         used, locked, dirty, negative, (int)mfp->mf_neg_count, nfree);
  1139.         msg(IObuff);
  1140.         sprintf((char *)IObuff, "Total mem used is %ld bytes", total_mem_used);
  1141.         msg(IObuff);
  1142.     }
  1143. }
  1144. #endif
  1145.  
  1146. /*
  1147.  * open a swap file for a memfile
  1148.  */
  1149.     static void
  1150. mf_do_open(mfp, fname, trunc_file)
  1151.     MEMFILE        *mfp;
  1152.     char_u        *fname;
  1153.     int            trunc_file;
  1154. {
  1155.     mfp->mf_fname = fname;
  1156.     /*
  1157.      * Get the full path name before the open, because this is
  1158.      * not possible after the open on the Amiga.
  1159.      * fname cannot be NameBuff, because it must have been allocated.
  1160.      */
  1161.     mf_set_xfname(mfp);
  1162.  
  1163.     /*
  1164.      * try to open the file
  1165.      */
  1166.     mfp->mf_fd = open((char *)fname,
  1167.             (trunc_file ? (O_CREAT | O_RDWR | O_TRUNC) : (O_RDONLY)) | O_EXTRA
  1168.  
  1169. #ifdef AMIGA                /* Amiga has no mode argument */
  1170.                     );
  1171. #endif
  1172. #ifdef UNIX                    /* open in rw------- mode */
  1173.                     , (mode_t)0600);
  1174. #endif
  1175. #if defined(MSDOS) || defined(WIN32) || defined(__EMX__)
  1176.                     , S_IREAD | S_IWRITE);         /* open read/write */
  1177. #endif
  1178. #ifdef VMS                    /* open in rw------- mode */
  1179.                     , 0600);
  1180. #endif
  1181.  
  1182.     /*
  1183.      * If the file cannot be opened, use memory only
  1184.      */
  1185.     if (mfp->mf_fd < 0)
  1186.     {
  1187.         vim_free(mfp->mf_xfname);
  1188.         mfp->mf_fname = NULL;
  1189.         mfp->mf_xfname = NULL;
  1190.     }
  1191. }
  1192.